import { Injectable } from '@nestjs/common';
import { PageDto, RecahrgeDto } from './dto';
import { RechargeOrder } from '@app/db/entity/RechargeOrder';
import { User } from '@app/db/entity/User';
import { DbService } from 'apps/admin/src/db/db.service';
import { DataSource, FindOptionsWhere, In } from 'typeorm';
import { UserWalletLog } from '@app/db/entity/UserWalletLog';
import { RECHARGE_CHANNEL } from 'constant/RECHARGE_CHANNEL';
import { WALLET_LOG_TYPE } from 'constant/WALLET_LOG_TYPE';

@Injectable()
export class OrderService {
    constructor(
        private readonly db:DbService,
        private dataSource: DataSource,
    ){
        
    }

    async page(dto:PageDto) {
        
        let result:PaginationResult<RechargeOrder & {user? : User}> = {
            total : 0,
            rows : []
        }

        let where:FindOptionsWhere<RechargeOrder> = {
            
        }

        
        if(dto.orderNo) {
            where.orderNo = dto.orderNo
        }

        result.total = await this.db.rechargeOrder.count(where)

        if(result.total > 0) {
            result.rows = await this.db.rechargeOrder.pagination(dto.pageNo, dto.pageSize, where, null, {id : 'DESC'})
            
            if(result.rows.length > 0) {
                const userIds:number[] = []
                const userMap:{[key:string]:User} = {}


                result.rows.forEach(row => {
                    if(!userIds.includes(row.userId)) {
                        userIds.push(row.userId)
                    }
                })

                let users = await this.db.user.find({id : userIds.length == 0 ? userIds[0] : In(userIds)}, ['id', 'nickname', 'avatar'])
                users.forEach(user => {
                    userMap[user.id] = user
                })
                users = null

                result.rows.forEach(row => {
                    row.user = userMap[row.userId]
                })
            }
        
        }
        

        return result

    }


    private generateOrderNo(userId:number) {
        const date = new Date()
        const time = Math.floor(date.getTime() / 1000) % 1000000
        const year = date.getFullYear() % 100
        const month = String(date.getMonth() + 1).padStart(2, '0')
        const day = String(date.getDate()).padStart(2, '0')
        return 'b' + year + month + day + time + String(userId).padStart(10, '0')
    }

    async recharge(dto:RecahrgeDto) {
        const time = Math.floor(Date.now() / 1000)



        let order:{[key in keyof RechargeOrder]? : RechargeOrder[key]} = {
            orderNo : this.generateOrderNo(dto.userId),
            amount : String(dto.amount),
            rewardAmount : String(dto.rewardAmount),
            payChannel : RECHARGE_CHANNEL.PLATFORM,
            userId : dto.userId,
            
            createTime : time
        }


        const queryRunner = await this.dataSource.createQueryRunner()
        await queryRunner.connect();
        await queryRunner.startTransaction();


        try {
            let user = await queryRunner.manager.findOne<User>(User, {
                where : {id : order.userId},
                select : ['amount', 'rewardAmount'],
                lock : {
                    mode : 'pessimistic_read'
                }
            })

            if(!user) {
                await queryRunner.rollbackTransaction();
                return false
            }


            //加入充值订单
            const r0 = await queryRunner.manager.insert<RechargeOrder>(RechargeOrder, order)
            if(!r0.raw || r0.raw.affectedRows < 1) {
                await queryRunner.rollbackTransaction();
                return false
            }

            const orderId = r0.generatedMaps[0][this.db.rechargeOrder.primaryKey]



            //用户钱包更新
            let updateData:{amount:number, rewardAmount?:number} = {
                amount : (Number(user.amount) + Number(order.amount))
            }

            //钱包记录
            const log:{[key in keyof UserWalletLog]? : UserWalletLog[key]} = {
                amount : order.amount,
                beforeAmount : String(user.amount),
                beforeRewardAmount : String(user.rewardAmount),
                afterAmount : updateData.amount.toFixed(2),

                userId : order.userId,
                createTime : time,
                type : WALLET_LOG_TYPE.PLATFORM_PAY
            }

            const rewardAmount = Number(order.rewardAmount)
            
            if(rewardAmount > 0) {
                updateData.rewardAmount = (Number(user.rewardAmount) + rewardAmount)

                log.rewardAmount = order.rewardAmount
                log.afterRewardAmount = updateData.rewardAmount.toFixed(2)
                
            }
            
            //更改用户余额
            const r1 = await queryRunner.manager.update<User>(User, { id : order.userId }, updateData)
            if(r1.affected < 1) {
                await queryRunner.rollbackTransaction();
                return false
            }

            

            log.relationId = orderId

            //加入钱包记录
            const r3 = await queryRunner.manager.insert<UserWalletLog>(UserWalletLog, log)
            if(!r3.raw || r3.raw.affectedRows < 1) {
                await queryRunner.rollbackTransaction();
                return false
            }

        
            await queryRunner.commitTransaction()

            return true
            
        } catch (error) {
            console.log(error)
            await queryRunner.rollbackTransaction();

            return false
        } finally {
            await queryRunner.release();
        }

    }
}
